package com.gitee.minimalismstyle.fresh.common.document.domain

import org.apache.commons.lang3.reflect.FieldUtils
import kotlin.reflect.KClass


class ExeclDataMap: LinkedHashMap<String, Any>() {

    fun <T : Any> getList(name: String, clazz: KClass<T>):  MutableList<T> {
        return getList(name, clazz.java)
    }

    fun <T : Any> getList(name: String, clazz: Class<T>): MutableList<T> {
        val data: MutableList<T> = arrayListOf()
        var list: List<ExeclDataMap> = this[name] as List<ExeclDataMap>
        if(!list.isNullOrEmpty()){
            list.forEach { map ->
                val obj: T = map.getObject(clazz)
                data.add(obj)
            }

        }

        return data
    }

    fun <T : Any> getObject(clazz: KClass<T>): T {
        return getObject(clazz.java)
    }

    fun <T : Any> getObject(clazz: Class<T>): T {
        return getObject(this, clazz)
    }

    fun <T : Any> getObject(name: String, clazz: KClass<T>): T {
        return getObject(name, clazz.java)
    }

    fun <T : Any> getObject(name: String, clazz: Class<T>): T {
        var map : ExeclDataMap = this[name] as ExeclDataMap
        return getObject(map, clazz)
    }

    private fun <T : Any> getObject(map: ExeclDataMap, clazz: Class<T>): T {
        val obj = clazz.getConstructor().newInstance()
        if(!map.isNullOrEmpty()){
            clazz.declaredFields.forEach {
                val cell = map[it.name]
                if(cell != null && cell is Cell){
                    FieldUtils.writeDeclaredField(obj, it.name, cell.value, true)
                }
            }

        }

        return obj
    }

    fun isAllValid(): Boolean{
        return isAllValid(this)
    }

    private fun isAllValid(map: ExeclDataMap): Boolean{
        map.values.forEach {
            if(it is Cell){
                if(!it.valid){
                    return false
                }
            }else if(it is ExeclDataMap){
                if(!isAllValid(it)){
                    return false
                }
            }else if(it is List<*>){
                return !it.any {m -> isAllValid(m as ExeclDataMap) == false }
            }
        }
        return true
    }
}